package org.net5ijy.oauth2.client.base;

import static org.net5ijy.commons.http.constants.StatusCode.*;
import static org.net5ijy.oauth2.client.base.BaseAuthorizationCodeMode.*;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.net5ijy.commons.http.HttpClientHttp;
import org.net5ijy.commons.http.response.HtmlResponseHolder;
import org.net5ijy.commons.http.response.ResponseHolder;
import org.net5ijy.oauth2.client.base.BaseAuthorizationCodeMode.AuthorizationCodeBaseEntity;

/**
 * 界面版授权码模式客户端通用方法抽取
 *
 * @author XGF
 * @date 2020/8/16 15:56
 */
@Slf4j
public class AuthorizationCodeMode {

  public static ResponseHolder start(String startUrl) throws IOException {

    try (HttpClientHttp clientHttp = new HttpClientHttp()) {
      return clientHttp.html(startUrl, null, null);
    } catch (IOException e) {
      log.error(e.getMessage(), e);
      throw e;
    }
  }

  public static ResponseHolder login(
      String loginUrl, String username, String password, String sessionId) throws IOException {

    try (HttpClientHttp clientHttp = new HttpClientHttp()) {
      return clientHttp.postHtml(loginUrl,
          new HashMap<String, String>(1) {
            {
              put("Cookie", "JSESSIONID=" + sessionId);
            }
          },
          new HashMap<String, String>(2) {
            {
              put("username", username);
              put("password", password);
            }
          });
    } catch (IOException e) {
      log.error(e.getMessage(), e);
      throw e;
    }
  }

  public static ResponseHolder start(String startUrl, String sessionId) throws IOException {

    try (HttpClientHttp clientHttp = new HttpClientHttp()) {
      return clientHttp.html(startUrl,
          new HashMap<String, String>(1) {
            {
              put("Cookie", "JSESSIONID=" + sessionId);
            }
          },
          null);
    } catch (IOException e) {
      log.error(e.getMessage(), e);
      throw e;
    }
  }

  public static ResponseHolder approve(
      String sessionId, String scope, String baseUrl, String authorizeUrl, String referer)
      throws IOException {

    try (HttpClientHttp clientHttp = new HttpClientHttp()) {

      // 在页面里面选择Approve然后提交

      HtmlResponseHolder postHtml = clientHttp.postHtml(
          authorizeUrl,
          new HashMap<String, String>(2) {
            {
              put("Cookie", "JSESSIONID=" + sessionId);
              put("Referer", referer);
              put("Origin", baseUrl);
              put("Sec-Fetch-User", "?1");
              put("Sec-Fetch-Site", "same-origin");
              put("Sec-Fetch-Mode", "navigate");
              put("Upgrade-Insecure-Requests", "1");
              put("User-Agent",
                  "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36");
            }
          }, new HashMap<String, String>(1) {
            {
              put("scope." + scope, "true");
              put("user_oauth_approval", "true");
              put("authorize", "Authorize");
            }
          });

      int statusCode = postHtml.getStatusCode();

      System.out.println("approve status: " + statusCode);

      // 不是301、302状态码
      if (statusCode != STATUS_PERMANENTLY_MOVED && statusCode != STATUS_TEMPORARILY_MOVED) {
        throw new RuntimeException("获取授权码失败");
      }

      return postHtml;

    } catch (IOException e) {
      log.error(e.getMessage(), e);
      throw e;
    }
  }

  public static Map getToken(AuthorizationCodeBaseEntity entity) throws IOException {

    // 第1步模拟浏览器访问
    ResponseHolder start = start(entity.getStartUrl());

    // 获取session id以便维持会话
    String jsessionid = start.cookieValue("JSESSIONID");

    // 第2步模拟浏览器访问，进行登录认证
    ResponseHolder responseHolder = login(entity.getLoginUrl(), entity.getUsername(),
        entity.getPassword(), jsessionid);

    int statusCode = responseHolder.getStatusCode();

    System.out.println("login response code: " + statusCode);

    jsessionid = responseHolder.cookieValue("JSESSIONID");

    // 重新访问一次初始授权页
    ResponseHolder start1 = start(entity.getStartUrl(), jsessionid);

    int statusCode1 = start1.getStatusCode();

    String code;

    if (statusCode1 == STATUS_PERMANENTLY_MOVED || statusCode1 == STATUS_TEMPORARILY_MOVED) {

      code = resolveCode(start1);

    } else {

      // 第3步模拟选择Approve然后提交表单
      ResponseHolder approveHtml =
          approve(jsessionid, entity.getScope(),
              entity.getBaseUrl(), entity.getAuthorizeUrl(), entity.getStartUrl());

      // 会重定向到http://localhost:8080并且携带code

      // 第4步获取授权码
      code = resolveCode(approveHtml);
    }

    // 打印一下code
    System.out.println("code: " + code);

    // 第5步获取token
    HtmlResponseHolder tokenResponse =
        token(
            code, entity.getTokenUrl(), entity.getRedirectUrl(), entity.getAppId(),
            entity.getSecret(), entity.getScope());

    String content = tokenResponse.getContent();
    System.out.println(content);

    ObjectMapper mapper = new ObjectMapper();
    Map value = mapper.readValue(content, Map.class);

    value.put("session", jsessionid);

    System.out.println("Token map: " + value);

    return value;
  }
}
